package com.thinkit.bigdata.web.service.impl.tagging;

import com.google.common.base.Strings;
import com.thinkit.bigdata.core.util.CastUtil;
import com.thinkit.bigdata.core.util.DateFormatUtil;
import com.thinkit.bigdata.core.util.es.ESUtil;
import com.thinkit.bigdata.web.controller.pubmet.PubMethod;
import com.thinkit.bigdata.web.coremet.SystemStatic;
import com.thinkit.bigdata.web.dao.bus.BusTagMapper;
import com.thinkit.bigdata.web.dao.tagging.TaggingDao;
import com.thinkit.bigdata.web.model.BaseEntity;
import com.thinkit.bigdata.web.model.bus.BusTag;
import com.thinkit.bigdata.web.model.bus.BusTagExample;
import com.thinkit.bigdata.web.model.es.audioEs.VoiceInfoDto;
import com.thinkit.bigdata.web.model.result.Constants;
import com.thinkit.bigdata.web.model.result.HtmlResult;
import com.thinkit.bigdata.web.model.sec.User;
import com.thinkit.bigdata.web.model.tagging.SysTags;
import com.thinkit.bigdata.web.model.tagging.TagDetails;
import com.thinkit.bigdata.web.model.tagging.TaggingSource;
import com.thinkit.bigdata.web.service.tagging.TaggingService;
import org.apache.log4j.Logger;
import org.apache.lucene.search.join.ScoreMode;
import org.apache.shiro.SecurityUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

@Service
public class TaggingServiceImpl implements TaggingService {

    private static Logger logger = Logger.getLogger(TaggingServiceImpl.class);

    @Resource
    private TaggingDao taggingDao;

    @Resource
    private ESUtil esUtil;

    @Resource
    private BusTagMapper tagMapper;

    @Override
    public BoolQueryBuilder getQuery(String logTxt, HttpServletRequest params) {
        String provinceCode = params.getParameter("provinceCode");//省份
        String customerlocs = params.getParameter("customerloc");//归属地
        String callDirection = params.getParameter("callDirection");//呼叫类型
        String serialNumber = params.getParameter("serialNumber");//录音流水
        String seatGroup = params.getParameter("seatGroup");//坐席班组
        String seatId = params.getParameter("seatId");//坐席工号
        String seatName = params.getParameter("seatName");//坐席工号
        String proPhoneNum = params.getParameter("proPhoneNum");//受理号码
        String customerNumber = params.getParameter("customerNumber");//客户号码
        String customerLevels = params.getParameter("customerLevel");//客户星级f
        String customerSign = params.getParameter("customerSign");//重要客户
        String onHooks = params.getParameter("onHook");//挂机方
        String callStartTime = params.getParameter("callStartTime");//通话开始时间
        String callEndTime = params.getParameter("callEndTime");//通话结束时间
        String holdDurationMin = params.getParameter("holdDurationMin");//通话时长小值
        String holdDurationMax = params.getParameter("holdDurationMax");//通话时长大值
        String reCallFlag = params.getParameter("reCallFlag");//重复来电
        String satisfactions = params.getParameter("satisfaction");//满意度
        String proStatus = params.getParameter("proStatus");//录音流水
        String inputTimeBegin = params.getParameter("inputTimeBegin");//入库时间
        String inputTimeEnd = params.getParameter("inputTimeEnd");//入库时间
        String sysTagFlags = params.getParameter("sysTagFlag");//系统打标标识
        String appealFlags = params.getParameter("appealFlag");//业务场景标识
        String sysTagIds = params.getParameter("sysTagIds");//系统标签_标签ids
        String sysOperator = params.getParameter("sysOperator");//系统标签_运算符  //should  ||   must
        String taggingError = params.getParameter("taggingError");//标签标注统计-错误量-的查询条件
        logger.info(logTxt + "provinceCode = " + provinceCode);
        logger.info(logTxt + "customerlocs = " + customerlocs);
        logger.info(logTxt + "callDirection = " + callDirection);
        logger.info(logTxt + "serialNumber = " + serialNumber);
        logger.info(logTxt + "seatGroup = " + seatGroup);
        logger.info(logTxt + "seatId = " + seatId);
        logger.info(logTxt + "seatName = " + seatName);
        logger.info(logTxt + "proPhoneNum = " + proPhoneNum);
        logger.info(logTxt + "customerNumber = " + customerNumber);
        logger.info(logTxt + "customerLevel = " + customerLevels);
        logger.info(logTxt + "customerSign = " + customerSign);
        logger.info(logTxt + "onHooks = " + onHooks);
        logger.info(logTxt + "callStartTime = " + callStartTime);
        logger.info(logTxt + "callEndTime = " + callEndTime);
        logger.info(logTxt + "holdDurationMin = " + holdDurationMin);
        logger.info(logTxt + "holdDurationMax = " + holdDurationMax);
        logger.info(logTxt + "reCallFlag = " + reCallFlag);
        logger.info(logTxt + "satisfactions = " + satisfactions);
        logger.info(logTxt + "proStatus = " + proStatus);
        logger.info(logTxt + "inputTimeBegin = " + inputTimeBegin);
        logger.info(logTxt + "inputTimeEnd = " + inputTimeEnd);
        logger.info(logTxt + "sysTagFlags = " + sysTagFlags);
        logger.info(logTxt + "appealFlags = " + appealFlags);
        logger.info(logTxt + "sysTagIds = " + sysTagIds);
        logger.info(logTxt + "sysOperator = " + sysOperator);
        logger.info(logTxt + "taggingError = " + taggingError);
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //数据权限
        esUtil.formatQ(boolQuery, seatId);
        //标签标注统计的查询条件组装
        if (!Strings.isNullOrEmpty(taggingError)) {
            if (!Strings.isNullOrEmpty(sysTagIds)) {
                BoolQueryBuilder shouldOrMustQ = new BoolQueryBuilder();
                for (String tagName : sysTagIds.split(",")) {
                    BoolQueryBuilder proQ = new BoolQueryBuilder();
                    proQ.must(
                            QueryBuilders.nestedQuery(
                                    "sysTags",
                                    QueryBuilders.boolQuery()
                                            .must(QueryBuilders.wildcardQuery("sysTags.tagName", tagName + "*"))
                                            .must(
                                                    QueryBuilders.nestedQuery(
                                                            "sysTags.tagDetails",
                                                            QueryBuilders.matchQuery("sysTags.tagDetails.matchStatus", BaseEntity.MATCHSTATUS_NO),
                                                            ScoreMode.None
                                                    )
                                            ),
                                    ScoreMode.None
                            )
                    );
                    if ("should".equals(sysOperator)) {
                        shouldOrMustQ.should(proQ);
                    } else {
                        shouldOrMustQ.must(proQ);
                    }
                }
                boolQuery.must(shouldOrMustQ);
            } else {
                boolQuery.must(
                        QueryBuilders.nestedQuery("sysTags",
                                QueryBuilders.nestedQuery(
                                        "sysTags.tagDetails",
                                        QueryBuilders.matchQuery("sysTags.tagDetails.matchStatus", BaseEntity.MATCHSTATUS_NO),
                                        ScoreMode.None
                                ),
                                ScoreMode.None)
                );
            }
        } else {
            if (!Strings.isNullOrEmpty(sysTagIds)) {
                BoolQueryBuilder shouldOrMustQ = new BoolQueryBuilder();
                for (String tagName : sysTagIds.split(",")) {
                    BoolQueryBuilder proQ = new BoolQueryBuilder();
                    proQ.must(
                            QueryBuilders.nestedQuery(
                                    "sysTags",
                                    QueryBuilders.boolQuery()
                                            .must(QueryBuilders.wildcardQuery("sysTags.tagName", tagName + "*")),
                                    ScoreMode.None
                            )
                    );
                    if ("should".equals(sysOperator)) {
                        shouldOrMustQ.should(proQ);
                    } else {
                        shouldOrMustQ.must(proQ);
                    }
                }
                boolQuery.must(shouldOrMustQ);
            }
        }
        boolQuery.must(
                QueryBuilders.nestedQuery(
                        "sysTags",
                        QueryBuilders.existsQuery("sysTags.tagId"),
                        ScoreMode.None
                )
        );

        //省份
        if (!Strings.isNullOrEmpty(provinceCode)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.provinceCode", provinceCode));
        }
        if (!Strings.isNullOrEmpty(customerlocs)) {
            PubMethod.formatPC(boolQuery, Arrays.asList(customerlocs.split(",")));
        }
        if (!Strings.isNullOrEmpty(serialNumber)) {
            boolQuery.must(QueryBuilders.wildcardQuery("serialNumber", "*" + serialNumber + "*"));
        }
        if (!Strings.isNullOrEmpty(callDirection)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.callDirection", callDirection));
        }
        //挂机方
        if (!Strings.isNullOrEmpty(onHooks)) {
            PubMethod.formatOnHook(boolQuery, Arrays.asList(onHooks.split(",")));
        }
        if (!Strings.isNullOrEmpty(customerNumber)) {
            boolQuery.must(QueryBuilders.wildcardQuery("voiceInfo.customerNum", "*" + customerNumber + "*"));
        }
        if (!Strings.isNullOrEmpty(reCallFlag)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.reCallFlag", reCallFlag));
        }
        if (!Strings.isNullOrEmpty(proPhoneNum)) {
            boolQuery.must(QueryBuilders.wildcardQuery("voiceInfo.proPhoneNum", "*" + proPhoneNum + "*"));
        }
        //客户星级
        if (!Strings.isNullOrEmpty(customerLevels)) {
            PubMethod.formatCustomerLevel(boolQuery, Arrays.asList(customerLevels.split(",")));
        }
        if (!Strings.isNullOrEmpty(customerSign)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.customerSign", customerSign));
        }
        //满意度
        if (!Strings.isNullOrEmpty(satisfactions)) {
            PubMethod.formatSatisfactions(boolQuery, Arrays.asList(satisfactions.split(",")));
        }
        if (!Strings.isNullOrEmpty(seatName)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.seatName", seatName));
        }
        if (!Strings.isNullOrEmpty(seatGroup)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.groupId", seatGroup));
        }
        if (!Strings.isNullOrEmpty(callStartTime)) {
            PubMethod.formatTime(boolQuery, callStartTime, callEndTime);
        }
        if (!Strings.isNullOrEmpty(inputTimeBegin)) {
            boolQuery.must(QueryBuilders.rangeQuery("voiceInfo.inputTime").gte(inputTimeBegin));
        }
        if (!Strings.isNullOrEmpty(inputTimeEnd)) {
            boolQuery.must(QueryBuilders.rangeQuery("voiceInfo.inputTime").lte(inputTimeEnd));
        }
        if (!Strings.isNullOrEmpty(holdDurationMin)) {
            boolQuery.must(QueryBuilders.rangeQuery("voiceInfo.holdDuration").gte(holdDurationMin));
        }
        if (!Strings.isNullOrEmpty(holdDurationMax)) {
            boolQuery.must(QueryBuilders.rangeQuery("voiceInfo.holdDuration").lte(holdDurationMax));
        }
        if (!Strings.isNullOrEmpty(proStatus)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.proStatus", proStatus));
        }
        if (!Strings.isNullOrEmpty(sysTagFlags)) {
            BoolQueryBuilder shuldQ = new BoolQueryBuilder();
            for (String sysTagFlag : sysTagFlags.split(",")) {
                shuldQ.should(QueryBuilders.matchQuery("sysTagFlag", sysTagFlag));
            }
            boolQuery.must(shuldQ);
        }
        if (!Strings.isNullOrEmpty(appealFlags)) {
            BoolQueryBuilder shuldQ = new BoolQueryBuilder();
            for (String appealFlag : appealFlags.split(",")) {
                shuldQ.should(QueryBuilders.matchQuery("appealFlag", appealFlag));
            }
            boolQuery.must(shuldQ);
        }
        return boolQuery;
    }

    @Override
    public HtmlResult searchData(HttpServletRequest request) throws InvocationTargetException, IllegalAccessException {
        String logTxt = "【标签标注统计-音频列表方法Impl】";
        logger.info(logTxt);
        int pageNum = Integer.parseInt(request.getParameter("pageNum"));//起始页
        int pageSize =Integer.parseInt(request.getParameter("pageSize"));//每页条数
        BoolQueryBuilder boolQuery = getQuery(logTxt, request);
        String[] includes = new String[]{"serialNumber", "voiceInfo"};
        return HtmlResult.success(
                taggingDao.formatVoice(taggingDao.getTaggingList(boolQuery, includes, pageNum, pageSize)),
                SystemStatic.crud.queryQBuilderAllByMes(SystemStatic.STATISTICS_ES_INDEX, SystemStatic.STATISTICS_ES_TYPE, boolQuery)
        );
    }

    @Override
    public HtmlResult getTaggingList(String serialNumber) {
        String[] includes = new String[]{
                "sysTags"
        };
        BoolQueryBuilder boolQuery = new BoolQueryBuilder();
        boolQuery.must(QueryBuilders.matchQuery("serialNumber", serialNumber));
        List<TaggingSource> taggingSources = taggingDao.getTaggingList(boolQuery, includes, null, null);
        if (taggingSources.isEmpty()) {
            return HtmlResult.success(new ArrayList<>());
        }
        return HtmlResult.success(taggingSources.get(0).getSysTags());
    }

    @Override
    public HtmlResult getTaggingMesList(String serialNumber, String tagId) {
        String[] includes = new String[]{
                "sysTags.tagId",
                "sysTags.tagDetails.startTime",
                "sysTags.tagDetails.endTime",
                "sysTags.tagDetails.content",
                "sysTags.tagDetails.matchStatus",
                "sysTags.tagDetails.proNote",
                "sysTags.tagDetails.proTime",
                "sysTags.tagDetails.proUserId"
        };
        BoolQueryBuilder boolQuery = new BoolQueryBuilder();
        boolQuery.must(QueryBuilders.matchQuery("serialNumber", serialNumber))
                .must(QueryBuilders.nestedQuery(
                        "sysTags",
                        QueryBuilders.boolQuery().must(
                                QueryBuilders.matchQuery("sysTags.tagId", tagId)
                        ),
                        ScoreMode.None
                ));
        List<TaggingSource> taggingSources = taggingDao.getTaggingList(boolQuery, includes, null, null);
        List<SysTags> tagsList = taggingSources.get(0).getSysTags();
        for (SysTags tags : tagsList) {
            if (tags.getTagId().toString().equals(tagId)) {
                return HtmlResult.success(tags.getTagDetails());
            }
        }
        return HtmlResult.failure();
    }

    @Override
    public HtmlResult judgeTaggingError(String serialNumber, String tagId, Integer matchStatus, String proNote, String startTime, String endTime) {
        User user = (User) SecurityUtils.getSubject().getSession().getAttribute(Constants.SESSION_USER_INFO);
        String date = DateFormatUtil.getNowDataTime();
        TaggingSource source = taggingDao.getSourceBySerialNumber(serialNumber);
        for (SysTags tags : source.getSysTags()) {
            if (source.getSysTags() == null) {
                continue;
            }
            if (tags.getTagId().toString().equals(tagId)) {
                tags.setProNote(proNote);
                tags.setProTime(date);
                tags.setProUserId(user.getAccount());
                for (TagDetails detail : tags.getTagDetails()) {
                    if (detail.getStartTime() == Double.parseDouble(startTime)
                            && detail.getEndTime() == Double.parseDouble(endTime)
                    ) {
                        detail.setMatchStatus(matchStatus);
                        detail.setProNote(proNote);
                        detail.setProTime(date);
                        detail.setProUserId(user.getAccount());
                    }
                }
            }
        }
        return taggingDao.updateSource(source);
    }

    @Override
    public List<Map<String, Object>> taggingStatistics(HttpServletRequest request, String logTxt) {
        String provinceCode = request.getParameter("provinceCode");
        String tagNames = request.getParameter("tagNames");
        List<Map<String, Object>> resultList = new ArrayList<>();
        BusTagExample example = new BusTagExample();
        example.createCriteria().andTagtypeNotEqualTo(BaseEntity.PROTYPE_ZX);
        //tagNames 为空 统计
        if (Strings.isNullOrEmpty(tagNames)) {
            Map<String, Object> resultMap = new HashMap<>();
            BoolQueryBuilder boolQuery = new BoolQueryBuilder();
            getSourceByVoice(request, logTxt, boolQuery);
            Map<String, Long> result = SystemStatic.crud.getTaggingAggSumY(
                    SystemStatic.STATISTICS_ES_INDEX,
                    SystemStatic.STATISTICS_ES_TYPE,
                    boolQuery,
                    ""
            );
            int allTagNum = result.get("allTagNum").intValue();
            int errorTagNum = result.get("errorTagNum").intValue();
            //语义匹配量
            resultMap.put("allTagNum", allTagNum);
            //匹配错误量
            resultMap.put("errorTagNum", errorTagNum);
            //匹配正确率
            resultMap.put("successTagNum", CastUtil.formatDec((allTagNum - errorTagNum), allTagNum));
            //标签名称
            resultMap.put("tagId", "");
            resultMap.put("tagName", "");
            //省份
            resultMap.put("provinceCode", provinceCode);
            resultList.add(resultMap);
        }
        //tagNames不为空 按照tagId统计
        else {
            for (String tagName : tagNames.split(",")) {
                Map<String, Object> resultMap = new HashMap<>();
                BoolQueryBuilder boolQuery = new BoolQueryBuilder();
                getSourceByVoice(request, logTxt, boolQuery);
                if (!Strings.isNullOrEmpty(tagNames)) {
                    boolQuery.must(QueryBuilders.nestedQuery(
                            "sysTags",
                            QueryBuilders.wildcardQuery("sysTags.tagName", tagName + "*"),
                            ScoreMode.None
                    ));
                }
                Map<String, Long> result = SystemStatic.crud.getTaggingAggSumY(
                        SystemStatic.STATISTICS_ES_INDEX,
                        SystemStatic.STATISTICS_ES_TYPE,
                        boolQuery,
                        tagName
                );
                //语义匹配量
                int allTagNum = result.get("allTagNum").intValue();
                //匹配错误量
                int errorTagNum = result.get("errorTagNum").intValue();
                //语义匹配量
                resultMap.put("allTagNum", allTagNum);
                //匹配错误量
                resultMap.put("errorTagNum", errorTagNum);
                //匹配正确率
                resultMap.put("successTagNum", CastUtil.formatDec((allTagNum - errorTagNum), allTagNum));
                //标签名称
                BusTagExample example1 = new BusTagExample();
                example1.createCriteria().andContentEqualTo(tagNames).andTagtypeNotEqualTo(BaseEntity.PROTYPE_ZX);
                BusTag busTag = tagMapper.selectByExample(example).get(0);
                resultMap.put("tagId", busTag.getContent());
                resultMap.put("tagName", tagName);
                //省份
                resultMap.put("provinceCode", provinceCode);
                resultList.add(resultMap);
            }
        }
        return resultList;
    }

    private void getSourceByVoice(HttpServletRequest request, String logTxt, BoolQueryBuilder boolQuery) {
        String provinceCode = request.getParameter("provinceCode");
        String satisfactions = request.getParameter("satisfaction");//满意度
        String customerLevels = request.getParameter("customerLevels");//客户星级
        String reCallFlag = request.getParameter("reCallFlag");//是否重复来电
        String callStartTime = request.getParameter("callStartTime");
        String callEndTime = request.getParameter("callEndTime");
        String tagNames = request.getParameter("tagNames");
        logger.info(logTxt + "provinceCode = " + provinceCode);
        logger.info(logTxt + "callStartTime = " + callStartTime);
        logger.info(logTxt + "callEndTime = " + callEndTime);
        logger.info(logTxt + "satisfactions = " + satisfactions);
        logger.info(logTxt + "customerLevels = " + customerLevels);
        logger.info(logTxt + "reCallFlag = " + reCallFlag);
        logger.info(logTxt + "tagNames = " + tagNames);
        boolQuery.must(QueryBuilders.rangeQuery("voiceInfo.callStartTime").gte(callStartTime).lte(callEndTime));
        if (!Strings.isNullOrEmpty(provinceCode)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.provinceCode", provinceCode));
        }
        //重复来电
        if (!Strings.isNullOrEmpty(reCallFlag)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.reCallFlag", reCallFlag));
        }
        //客户星级
        esUtil.formatShouldQ(customerLevels, boolQuery, "voiceInfo.customerLevel");
        //满意度
        esUtil.formatShouldQ(satisfactions, boolQuery, "voiceInfo.satisfaction");
        //数据权限
        esUtil.formatQ(boolQuery, null);
    }

    private void getMapList(List<Map<String, String>> mapList, List<TaggingSource> tagSources) {
        for (TaggingSource source : tagSources) {
            if (source.getSysTags() == null) {
                continue;
            }
            for (SysTags sysTag : source.getSysTags()) {
                for (TagDetails detail : sysTag.getTagDetails()) {
                    if (BaseEntity.MATCHSTATUS_NO == detail.getMatchStatus()) {
                        Map<String, String> resultMap = new HashMap<>();
                        resultMap.put("provinceCode", source.getVoiceInfo().getProvince());
                        resultMap.put("serialNumber", source.getSerialNumber());
                        resultMap.put("tagName", sysTag.getTagName());
                        resultMap.put("startTime", detail.getStartTime().toString());
                        resultMap.put("endTime", detail.getEndTime().toString());
                        resultMap.put("content", detail.getContent());
                        resultMap.put("matchStatus", detail.getMatchStatus() == BaseEntity.MATCHSTATUS_YES ? "正确" : "错误");
                        resultMap.put("proNote", detail.getProNote());
                        resultMap.put("proTime", detail.getProTime());
                        resultMap.put("proUserId", detail.getProUserId());
                        mapList.add(resultMap);
                    }
                }
            }
        }
    }

    @Override
    public List<Map<String, String>> getExportDate(HttpServletRequest request, String logTxt) {
        List<Map<String, String>> mapList = new ArrayList<>();
        BoolQueryBuilder boolQuery = getQuery(logTxt, request);
        String[] includes = new String[]{
                "serialNumber",
                "voiceInfo.province",
                "sysTags.tagId",
                "sysTags.tagName",
                "sysTags.proValue",
                "sysTags.tagDetails"
        };
        List<TaggingSource> tagSources = taggingDao.getTaggingList(boolQuery, includes, null, null);
        getMapList(mapList, tagSources);
        return mapList;
    }

    @Override
    public List<VoiceInfoDto> getErrorExportDate(HttpServletRequest request, String logTxt) throws InvocationTargetException, IllegalAccessException {
        BoolQueryBuilder boolQuery = getQuery(logTxt, request);
        String[] includes = new String[]{"serialNumber", "voiceInfo"};
        return taggingDao.formatVoice(taggingDao.getTaggingList(boolQuery, includes, null, null));
    }
}
